{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. GCN的问题\n",
    "\n",
    "GCN的训练方式是基于全图的形式，然而对于许多实际的业务场景，图的规模是非常巨大的，单张显卡的容量难以满足一张整图训练所需要的空间，所以小批量的训练方法对于大规模图数据的训练是十分必要的。\n",
    "\n",
    "此外，GCN要求在训练前知道整个图的结构信息，这也极大的限制了它的应用场景。\n",
    "\n",
    "\n",
    "## 2. GraphSage\n",
    "\n",
    "GraphSage通过采样邻居的策略将GCN的训练方式由全图(Full Batch)方式修改为以节点为中心的小批量(Mini Batch)的方式，这使得大规模图数据的分布式训练成为可能。\n",
    "\n",
    "\n",
    "![Visual illustration of the GraphSAGE sample and aggregate approach](images/graphsage_routing.png)\n",
    "\n",
    "### 2.1 采样邻居\n",
    "\n",
    "GNN模型中，图的信息聚合过程是沿着Graph Edge进行的，GNN中节点在第(k+1)层的特征只与其在(k)层的邻居有关，这种局部性质使得节点在(k)层的特征只与自己的k阶子图有关。因此对于k层网络，只需要采样Graph的k阶子图，就可以满足训练的需求。\n",
    "\n",
    "同时为了提升运算效率，对每个顶点的邻居节点进行有放回的采样，保证每个节点邻居个数都是相同的。这也是神经网络中处理数据的一种常用的策略。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sampling(src_nodes, sample_num, neighbor_table):\n",
    "    \"\"\"根据源节点采样指定数量的邻居节点，注意使用的是有放回的采样；\n",
    "    某个节点的邻居节点数量少于采样数量时，采样结果出现重复的节点\n",
    "    \n",
    "    Arguments:\n",
    "        src_nodes {list, ndarray} -- 源节点列表\n",
    "        sample_num {int} -- 需要采样的节点数\n",
    "        neighbor_table {dict} -- 节点到其邻居节点的映射表\n",
    "    \n",
    "    Returns:\n",
    "        np.ndarray -- 采样结果构成的列表\n",
    "    \"\"\"\n",
    "    results = []\n",
    "    for sid in src_nodes:\n",
    "        # 从节点的邻居中进行有放回地进行采样\n",
    "        res = np.random.choice(neighbor_table[sid], size=(sample_num, ))\n",
    "        results.append(res)\n",
    "    return np.asarray(results).flatten()\n",
    "\n",
    "\n",
    "def multihop_sampling(src_nodes, sample_nums, neighbor_table):\n",
    "    \"\"\"根据源节点进行多阶采样\n",
    "    \n",
    "    Arguments:\n",
    "        src_nodes {list, np.ndarray} -- 源节点id\n",
    "        sample_nums {list of int} -- 每一阶需要采样的个数\n",
    "        neighbor_table {dict} -- 节点到其邻居节点的映射\n",
    "    \n",
    "    Returns:\n",
    "        [list of ndarray] -- 每一阶采样的结果\n",
    "    \"\"\"\n",
    "    sampling_result = [src_nodes]\n",
    "\n",
    "    for k, hopk_num in enumerate(sample_nums):\n",
    "        hopk_result = sampling(sampling_result[k], hopk_num, neighbor_table)\n",
    "        sampling_result.append(hopk_result)\n",
    "    return sampling_result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 聚合邻居节点\n",
    "\n",
    "由于在图(Graph)中顶点的邻居是无序的，所以聚合函数最好是对称的，即无论如何改变输入的顺序，函数的输出结果总是不变的。\n",
    "\n",
    "常用的有如下几个聚合算子：\n",
    "\n",
    "1) 均值(Mean)/加和(Sum)聚合算子：\n",
    "\n",
    "$$Agg_{sum} = \\sigma (\\text{SUM} \\{W h_j + b\\}),  \\forall v_j \\in N(v_i)$$\n",
    "\n",
    "$$Agg_{mean} = \\sigma (\\text{MEAN} \\{W h_j + b\\}),  \\forall v_j \\in N(v_i)$$\n",
    "\n",
    "2) 池化(Pooling)聚合算子：\n",
    "\n",
    "$$Agg_{pool} = \\sigma (\\text{MAX} \\{W h_j + b\\}),  \\forall v_j \\in N(v_i)$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class NeighborAggregator(tf.keras.Model):\n",
    "    def __init__(self, input_dim, output_dim, \n",
    "                 use_bias=False, aggr_method=\"mean\"):\n",
    "        \"\"\"聚合节点邻居\n",
    "        Args:\n",
    "            input_dim: 输入特征的维度\n",
    "            output_dim: 输出特征的维度\n",
    "            use_bias: 是否使用偏置 (default: {False})\n",
    "            aggr_method: 邻居聚合方式 (default: {mean})\n",
    "        \"\"\"\n",
    "        super(NeighborAggregator, self).__init__()\n",
    "\n",
    "        self.input_dim = input_dim\n",
    "        self.output_dim = output_dim\n",
    "        self.use_bias = use_bias\n",
    "        self.aggr_method = aggr_method\n",
    "\n",
    "        self.weight = self.add_weight(shape = (self.input_dim, self.output_dim),\n",
    "                                      initializer = 'glorot_uniform',\n",
    "                                      name = 'kernel')\n",
    "\n",
    "        if self.use_bias:\n",
    "            self.bias = self.add_weight(shape = (self.input_dim, self.output_dim),\n",
    "                                        initializer = 'zero',\n",
    "                                        name = 'bias')\n",
    "\n",
    "    def call(self, neighbor_feature):\n",
    "        if self.aggr_method == \"mean\":\n",
    "            aggr_neighbor = tf.math.reduce_mean(neighbor_feature, axis = 1)\n",
    "        elif self.aggr_method == \"sum\":\n",
    "            aggr_neighbor = tf.math.reduce_sum(neighbor_feature, axis = 1)\n",
    "        elif self.aggr_method == \"max\":\n",
    "            aggr_neighbor = tf.math.reduce_max(neighbor_feature, axis = 1)\n",
    "        else:\n",
    "            raise ValueError(\"Unknown aggr type, expected sum, max, or mean, but got {}\"\n",
    "                             .format(self.aggr_method))\n",
    "        \n",
    "        neighbor_hidden = tf.matmul(aggr_neighbor, self.weight)\n",
    "        if self.use_bias:\n",
    "            neighbor_hidden += self.bias\n",
    "\n",
    "        return neighbor_hidden"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 模型训练\n",
    "\n",
    "这里我们使用的Cora数据集，该数据集由2708篇论文的特征、分类以及它们之间引用关系的5429条边组成，这些论文的类型被划分为7个类别:Case_Based、Genetic_Algorithms、Neural_Networks、Probabilistic_Methods、Reinforcement_Learning、Rule_Learning、Theory。最终实现的目标是，输入一篇论文的特征，就可以输出该论文属于哪个分类。\n",
    "\n",
    "可以看到，这里我们不再将整个Cora Dataset作为网络的输入，而是把Trainning Data分为一个个的Batch喂给模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = CoraData().data()\n",
    "\n",
    "train_index = np.where(data.train_mask)[0]\n",
    "train_label = data.y[train_index]\n",
    "test_index = np.where(data.test_mask)[0]\n",
    "val_index = np.where(data.val_mask)[0]\n",
    "\n",
    "model = GraphSage(input_dim=INPUT_DIM, hidden_dim=HIDDEN_DIM,\n",
    "                  num_neighbors_list=NUM_NEIGHBORS_LIST)\n",
    "\n",
    "loss_object = tf.keras.losses.CategoricalCrossentropy(from_logits=True)\n",
    "optimizer=tf.keras.optimizers.Adam(learning_rate=0.01, decay=5e-4)\n",
    "\n",
    "def train():\n",
    "    for e in range(EPOCHS):\n",
    "        for batch in range(NUM_BATCH_PER_EPOCH):\n",
    "            batch_src_index = np.random.choice(train_index, size=(BTACH_SIZE,))\n",
    "            batch_src_label = train_label[batch_src_index].astype(float)\n",
    "\n",
    "            batch_sampling_result = multihop_sampling(batch_src_index, NUM_NEIGHBORS_LIST, data.adjacency_dict)\n",
    "            batch_sampling_x = [data.x[np.array(idx.astype(np.int32))] for idx in batch_sampling_result]\n",
    "\n",
    "            with tf.GradientTape() as tape:\n",
    "                batch_train_logits = model(batch_sampling_x)\n",
    "                loss = loss_object(batch_src_label, batch_train_logits)\n",
    "                grads = tape.gradient(loss, model.trainable_variables)\n",
    "\n",
    "                optimizer.apply_gradients(zip(grads, model.trainable_variables))\n",
    "\n",
    "            print(\"Epoch {:03d} Batch {:03d} Loss: {:.4f}\".format(e, batch, loss))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在Tensorflow 2.0中实现代码时，出现：\"No gradients provided for any variable\"的错误，追了半天，才在stackoverflow上找到原因：\n",
    "\n",
    "https://stackoverflow.com/questions/58947679/no-gradients-provided-for-any-variable-in-tensorflow2-0\n",
    "\n",
    "> Yup, this is a mildly annoying thing about GradientTape. You cannot do anything to the tensors outside the tape context (with...) or the tape will \"lose track\". You can fix it by simply moving the addition into the context:\n",
    "\n",
    "在测试集和验证集上测试模型的精度的代码如下:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def test(index):\n",
    "    test_sampling_result = multihop_sampling(index, NUM_NEIGHBORS_LIST, data.adjacency_dict)\n",
    "    test_x = [data.x[idx.astype(np.int32)] for idx in test_sampling_result]\n",
    "    test_logits = model(test_x)\n",
    "    test_label = data.y[index]\n",
    "\n",
    "    ll = tf.math.equal(tf.math.argmax(test_label, -1), tf.math.argmax(test_logits, -1))\n",
    "    accuarcy = tf.reduce_mean(tf.cast(ll, dtype=tf.float32))\n",
    "\n",
    "    return accuarcy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后，把模型跑起来，看看效果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Process data ...\n",
      "Loading cora dataset...\n",
      "Dataset has 2708 nodes, 2708 edges, 1433 features.\n",
      "Epoch 000 train accuracy: 0.7733333110809326 val accuracy: 0.508571445941925 test accuracy:0.4180253744125366\n",
      "Epoch 001 train accuracy: 0.9599999785423279 val accuracy: 0.7142857313156128 test accuracy:0.6607789993286133\n",
      "Epoch 002 train accuracy: 0.9933333396911621 val accuracy: 0.7457143068313599 test accuracy:0.648097813129425\n",
      "Epoch 003 train accuracy: 1.0 val accuracy: 0.7142857313156128 test accuracy:0.6503623127937317\n",
      "Epoch 004 train accuracy: 1.0 val accuracy: 0.7142857313156128 test accuracy:0.6557971239089966\n",
      "Epoch 005 train accuracy: 1.0 val accuracy: 0.7200000286102295 test accuracy:0.6557971239089966\n",
      "Epoch 006 train accuracy: 1.0 val accuracy: 0.7171428799629211 test accuracy:0.65625\n",
      "Epoch 007 train accuracy: 1.0 val accuracy: 0.7342857122421265 test accuracy:0.65625\n",
      "Epoch 008 train accuracy: 1.0 val accuracy: 0.7285714149475098 test accuracy:0.6598731875419617\n",
      "Epoch 009 train accuracy: 1.0 val accuracy: 0.7142857313156128 test accuracy:0.6607789993286133\n",
      "Epoch 010 train accuracy: 1.0 val accuracy: 0.7200000286102295 test accuracy:0.6675724387168884\n",
      "Epoch 011 train accuracy: 1.0 val accuracy: 0.7171428799629211 test accuracy:0.6634963750839233\n",
      "Epoch 012 train accuracy: 1.0 val accuracy: 0.7314285635948181 test accuracy:0.6616848111152649\n",
      "Epoch 013 train accuracy: 1.0 val accuracy: 0.7114285826683044 test accuracy:0.6612318754196167\n",
      "Epoch 014 train accuracy: 1.0 val accuracy: 0.7114285826683044 test accuracy:0.6612318754196167\n",
      "Epoch 015 train accuracy: 1.0 val accuracy: 0.7028571367263794 test accuracy:0.6598731875419617\n",
      "Epoch 016 train accuracy: 1.0 val accuracy: 0.7171428799629211 test accuracy:0.6662137508392334\n",
      "Epoch 017 train accuracy: 1.0 val accuracy: 0.7142857313156128 test accuracy:0.6630434989929199\n",
      "Epoch 018 train accuracy: 1.0 val accuracy: 0.7228571176528931 test accuracy:0.6630434989929199\n",
      "Epoch 019 train accuracy: 1.0 val accuracy: 0.7171428799629211 test accuracy:0.6630434989929199\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x576 with 4 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from train import train\n",
    "\n",
    "train()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
